//
//  CSNateOAuthViewController.m
//  CairnStory
//  www.cairnstory.com
//
//  Created by saturna on 11. 3. 22..
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import <CommonCrypto/CommonHMAC.h>

#import "CSNateOAuthViewController.h"
#import "CSNateOAuthViewDelegate.h"
#import "CSNateOAuthResult.h"
#import "CSNateRequest.h"
#import "CSCommon.h"
#import "CSXMLObject.h"
#import "NSString+URLEncoding.h"
#import "NSData+Base64.h"


#pragma mark -
#pragma mark CSNateOAuthViewController (PrivateMethods)

@interface CSNateOAuthViewController (PrivateMethods)

- (void)tapBackButtonItem:(id)sender;
- (void)dismissView;
- (void)startProgressIndicator;
- (void)stopProgressIndicator;

#pragma mark -
- (NSString*)oauthParamForKey:(NSString*)key;
- (NSString*)generateOAuthSignatureWithOAuthNonce:(NSString*)oauthNonce
								andOauthTimestamp:(NSString*)oauthTimestamp
								  andRequestToken:(BOOL)requestToken;
- (NSString*)generateOAuthHeaderWithOAuthNonce:(NSString*)oauthNonce
							 andOAuthTimestamp:(NSString*)oauthTimestamp
							 andOAuthSignature:(NSString*)oauthSignature
							   andRequestToken:(BOOL)requestToken;

#pragma mark -
- (void)startSignIn;
- (NSDictionary*)requestOAuthRequestToken;
- (NSInteger)finalRequestToken:(NSURLRequest*)request;
- (NSDictionary*)requestOAuthAccessToken;

#pragma mark -
- (void)requestNateOnProfile;

@end



#pragma mark -
#pragma mark constants define

#define kDefaultNavigationTitle @"Nate/Cyworld Login"
#define kNateTagNateOnProfile 1


static NSString* kGetRequestTokenURLString = @"https://oauth.nate.com/OAuth/GetRequestToken/V1a";
static NSString* kOAuthAuthorizeURLString = @"https://oauth.nate.com/OAuth/Authorize/V1a";
static NSString* kGetAccessTokenURLString = @"https://oauth.nate.com/OAuth/GetAccessToken/V1a";

static NSString* kNateOAuthVersion = @"1.0";
static NSString* kNateOAuthSignatureMethod = @"HMAC-SHA1";



#pragma mark -
#pragma mark CSNateOAuthViewController
/*
1. start sign in (starSignIn)
 1) Request Token 요청 (requestOAuthRequestToken)
	 URLConnection sendSynchronousRequest 메소드 사용하여
	 oauth_token, oauth_token_secret를 얻는다.
 2) 인증화면 요청
	 UIWebView loadRequest 메소드 및 UIWebViewDelegate 사용하여
	 Nate 로그인 화면을 보여준다.
	 callback url 로드하려 할때 Access Token 요청
 3) Access Token 요청 (requestOAuthAccessToken)
	 UIWebViewDelegate에서 callback url로 redirect를 멈추고
	 URLConnection sendSynchronousRequest 메소드 사용하여
	 Access Token을 요청한다.
 4) NateOn Profile 요청 (requestNateOnProfile)
	 Access Token 요청 완료까지 인증절차가 끝나지만
	 추가로 사용자 정보를 조회한다.
	 NateRequest class를 사용한다.
*/
@implementation CSNateOAuthViewController

@synthesize initialHTMLString = m_initialHTMLString;



- (id)initWithConsumerKey:(NSString*)consumerKey
		andConsumerSecret:(NSString*)consumerSecret
			  andCallback:(NSString*)callback
			  andDelegate:(id<CSNateOAuthViewDelegate,NSObject>)delegate
{
	self = [super initWithNibName:NSStringFromClass([self class]) bundle:nil];
	if (self == nil)
	{
		return self;
	}

	m_finalRequestToken = -2;
	m_oauthParams = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
					 consumerKey, kNateKeyOAuthConsumerKey,
					 consumerSecret, kNateKeyOAuthConsumerSecret,
					 callback, kNateKeyOAuthCallback,
					 kNateOAuthVersion, kNateKeyOAuthVersion,
					 kNateOAuthSignatureMethod, kNateKeyOAuthSignatureMethod,
					 nil];

	m_delegate = [delegate retain];

	return self;
}


#pragma mark -
#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

	[self startProgressIndicator];
	[m_webView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
	 UIViewAutoresizingFlexibleWidth |
	 UIViewAutoresizingFlexibleRightMargin |
	 UIViewAutoresizingFlexibleTopMargin |
	 UIViewAutoresizingFlexibleHeight |
	 UIViewAutoresizingFlexibleBottomMargin];

	m_webView.backgroundColor = [UIColor clearColor];
	m_webView.delegate = nil;


	if (self.initialHTMLString == nil)
	{
		NSString* htmlFormat = @"<style>"
								"<!--"
								"BODY, TD, TH, A, PRE, P, B, SPAN, CODE {"
								"	color: #000000;"
								"	font-family: Arial,Helvetica,Tahoma,Verdana,sans-serif;"
								"	font-size: 12px;"
								"	text-decoration: none;"
								"}"
								"TD.td_text {"
								"	font-weight: normal;"
								"	background-color: #FFFFFF;"
								"	font-size: 15px;"
								"}"
								"-->"
								"</style>"
								"<table width=\"300\" height=\"300\""
								"align=\"center\" valign=\"middle\""
								"border=\"0\" cellpadding=\"3\" cellspacing=\"1\">"
								"<tr>"
								"<td align=\"center\" valign=\"middle\" class=\"td_text\">"
								"잠시만 기다려 주십시오.<br>"
								"Nate/Cyworld와 연결중입니다."
								"<br>"
								"<br>"
								"<img src=\"%@\" width=\"175\" height=\"55\" border=\"0\"/>"
								"</td>"
								"</tr>"
								"</table>";

		NSString* nateLogoPath = [[NSBundle mainBundle] pathForResource:@"logo_nate.png" ofType:nil];
		nateLogoPath = [[NSURL fileURLWithPath:nateLogoPath] absoluteString];

		self.initialHTMLString = [NSString stringWithFormat:htmlFormat, nateLogoPath];
	}
	if (self.initialHTMLString != nil)
	{
		[m_webView loadHTMLString:self.initialHTMLString baseURL:nil];
	}

	if (self.navigationItem.title == nil)
	{
		self.navigationItem.title = kDefaultNavigationTitle;
	}

	UIBarButtonItem* barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back"
																	  style:UIBarButtonItemStylePlain
																	 target:self
																	 action:@selector(tapBackButtonItem:)];
	self.navigationItem.leftBarButtonItem = barButtonItem;
	[barButtonItem release];

}


- (void)viewWillAppear:(BOOL)animated
{
	[super viewWillAppear:animated];
	[self startProgressIndicator];

	// *************************
	// 1. start sign in
	// *************************
	[self performSelector:@selector(startSignIn) withObject:nil afterDelay:1.0];
	[super viewWillAppear:animated];
}


- (void)viewWillDisappear:(BOOL)animated
{
	[super viewWillDisappear:NO];
}
- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:NO];
}


#pragma mark -
#pragma mark Memory management

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
}

- (void)dealloc
{
	m_webView.delegate = nil;
	[m_webView release];
	[m_progressIndicatorView release];

	[m_oauthParams release];
	[m_delegate release];
	[m_initialHTMLString release];

	[m_oauthResult release];
	if (m_nateRequest != nil)
	{
		[m_nateRequest release];
		m_nateRequest = nil;
	}

    [super dealloc];
}





#pragma mark -
#pragma mark UIWebViewDelegate

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request
 navigationType:(UIWebViewNavigationType)navigationType
{
	//if (DEBUG) CSLog(@"WEBVIEW URL ===> %@", [request URL]);
	if (m_finalRequestToken < 0)
	{
		// request token 정보를 수집한다.
		m_finalRequestToken = [self finalRequestToken:request];
	}

	if (m_finalRequestToken == 0)
	{
		[self dismissView];
		return NO;
	}
	else if (m_finalRequestToken > 0)
	{
		[self startProgressIndicator];

		// *************************
		// Access Token 요청
		// *************************
		NSDictionary* dicOAuthAccessToken = [[self requestOAuthAccessToken] retain];
		//if (DEBUG) CSLog(@"===> dicOAuthAccessToken : %@", dicOAuthAccessToken);

		if (dicOAuthAccessToken != nil)
		{
			[m_oauthParams addEntriesFromDictionary:dicOAuthAccessToken];
			[dicOAuthAccessToken release];

			m_oauthResult = [[CSNateOAuthResult alloc] initWithDictionary:m_oauthParams];

			// *************************
			// User Profile 요청
			// *************************
			[self requestNateOnProfile];
		}

		return NO;
	}

	return YES;
}

- (void)webViewDidStartLoad:(UIWebView*)webView
{
	//if (DEBUG) CSLog(@"===> %@", [[webView request] URL]);
	[self startProgressIndicator];
}

- (void)webViewDidFinishLoad:(UIWebView*)webView
{
	//if (DEBUG) CSLog(@"===> %@", [[webView request] URL]);
	[self stopProgressIndicator];
}

- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
{
	//if (DEBUG) CSLog(@"===> %@", [[webView request] URL]);
//	if (error.code == NSURLErrorCancelled || (error.code == 102 && [error.domain isEqual:@"WebKitErrorDomain"]))
//	{
//		return;
//	}

	[self stopProgressIndicator];
	if (m_delegate != nil &&
		[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
	{
		[m_delegate nateOAuthViewController:self
						   didFailWithError:error];
	}
	[self dismissView];
}




#pragma mark -
#pragma mark CSNateRequestDelegate

- (void)nateRequest:(CSNateRequest*)request
	didStartWithTag:(NSUInteger)nateTag
{
	// do nothing
}

- (void)nateRequest:(CSNateRequest*)request
  didSuccessWithTag:(NSUInteger)nateTag
	 withOutputType:(CSNateRequestOutputType)outputType
		 withResult:(id)result
{
	if (DEBUG) CSLog(@"===> %@", result);
	if (kNateTagNateOnProfile == nateTag)
	{
		CSXMLObject* xmlObject = (CSXMLObject*)result;
		NSInteger errorCode = [[[xmlObject subTextWithElementPath:@"/response/header/rcode"] substringFromIndex:3] intValue];
		if (errorCode != 0)
		{
			NSError* error = [[NSError alloc]
							  initWithDomain:@"nateErrDomain"
							  code:errorCode
							  userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
										[xmlObject subTextWithElementPath:@"/response/header/rmsg"], NSLocalizedDescriptionKey,
										nil]];
			[self stopProgressIndicator];
			if (m_delegate != nil &&
				[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
			{
				[m_delegate nateOAuthViewController:self
								   didFailWithError:error];
			}
			return;
		}


		NSDictionary* profileDic = [xmlObject subDictionaryWithElementPath:@"/response/body/profile"];
		NSArray* allKey = [profileDic allKeys];
		for (NSString* key in allKey)
		{
			if ([key isEqualToString:CSXMLObjectTextKey] == NO && [key isEqualToString:CSXMLObjectAttributesKey] == NO)
			{
				NSDictionary* dic = [profileDic objectForKey:key];
				[m_oauthResult setNateOnProfile:[dic objectForKey:CSXMLObjectTextKey] forKey:key];
			}
		}

		//if (DEBUG) CSLog(@"===> %@", m_oauthResult);
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didLoginWithAuthResult:)])
		{
			[m_delegate nateOAuthViewController:self
						 didLoginWithAuthResult:m_oauthResult];
		}
	}
	else
	{
		CSAssert1(FALSE, @"unsupported nate tag [%d]", nateTag);
	}
}

- (void)nateRequest:(CSNateRequest*)request
	 didFailWithTag:(NSUInteger)nateTag
		withMessage:(NSString*)alertMessage
		  withError:(NSError*)error
{
	//if (DEBUG) CSLog(@"===> %@ / %@", alertMessage, error);
	[self stopProgressIndicator];
	if (m_delegate != nil &&
		[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
	{
		[m_delegate nateOAuthViewController:self
						   didFailWithError:error];
	}
}

- (void)nateRequest:(CSNateRequest*)request
   didFinishWithTag:(NSUInteger)nateTag
{
	if (m_nateRequest != nil)
	{
		[m_nateRequest release];
		m_nateRequest = nil;
	}

	[self dismissView];
}




#pragma mark -
#pragma mark CSNateOAuthViewController (PrivateMethods)


- (void)tapBackButtonItem:(id)sender
{
	//if (DEBUG) CSLog(@"===>");
	[self stopProgressIndicator];
	if (m_delegate != nil &&
		[m_delegate respondsToSelector:@selector(nateOAuthViewControllerDidCancel:)])
	{
		[m_delegate nateOAuthViewControllerDidCancel:self];
	}

	[self dismissView];
}

- (void)dismissView
{
	//if (DEBUG) CSLog(@"===> topViewController - before -- %d", [[self navigationController] topViewController] == self);
	[self stopProgressIndicator];
	if (self.modalInPopover)
	{
		[[self navigationController] dismissModalViewControllerAnimated:NO];
	}
	else
	{
		[[self navigationController] popViewControllerAnimated:NO];
		if ([[self navigationController] topViewController] == self)
		{
			[self dismissView];
		}
	}
	//if (DEBUG) CSLog(@"===> topViewController - after -- %d", [[self navigationController] topViewController] == self);
}

- (void)startProgressIndicator
{
	if ([m_progressIndicatorView isAnimating])
	{
		return;
	}
	[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

	m_progressIndicatorView.hidden = NO;
	[m_progressIndicatorView startAnimating];

	self.view.userInteractionEnabled = NO;
}

- (void)stopProgressIndicator
{
	if ([m_progressIndicatorView isAnimating] == NO)
	{
		return;
	}
	[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

	m_progressIndicatorView.hidden = YES;
	[m_progressIndicatorView stopAnimating];

	self.view.userInteractionEnabled = YES;
}



#pragma mark -

- (NSString*)oauthParamForKey:(NSString*)key
{
	return [m_oauthParams objectForKey:key];
}



- (NSString*)generateOAuthSignatureWithOAuthNonce:(NSString*)oauthNonce
								andOauthTimestamp:(NSString*)oauthTimestamp
								   andRequestToken:(BOOL)requestToken
{
	// ------------------------------
	// query string
	NSMutableString* queryString = [[NSMutableString alloc] init];
	if (requestToken)
	{
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthCallback, [[self oauthParamForKey:kNateKeyOAuthCallback] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthConsumerKey, [[self oauthParamForKey:kNateKeyOAuthConsumerKey] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthNonce, [oauthNonce URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthSignatureMethod, [[self oauthParamForKey:kNateKeyOAuthSignatureMethod] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthTimestamp, oauthTimestamp];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthVersion, [[self oauthParamForKey:kNateKeyOAuthVersion] URLEncodedString]];
	}
	else
	{
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthConsumerKey, [[self oauthParamForKey:kNateKeyOAuthConsumerKey] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthNonce, [oauthNonce URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthSignatureMethod, [[self oauthParamForKey:kNateKeyOAuthSignatureMethod] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthTimestamp, oauthTimestamp];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthToken, [[self oauthParamForKey:kNateKeyOAuthToken] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthVerifier, [[self oauthParamForKey:kNateKeyOAuthVerifier] URLEncodedString]];
		[queryString appendString:@"&"];
		[queryString appendFormat:@"%@=%@", kNateKeyOAuthVersion, [[self oauthParamForKey:kNateKeyOAuthVersion] URLEncodedString]];
	}
	if (DEBUG) CSLog(@"===> queryString : [%@]", queryString);

	// ------------------------------
	// base string
	NSString* baseString;
	if (requestToken)
	{
		baseString = [NSString stringWithFormat:@"POST&%@&%@",
					  [kGetRequestTokenURLString URLEncodedString],
					  [queryString URLEncodedString]];
	}
	else
	{
		baseString = [NSString stringWithFormat:@"POST&%@&%@",
					  [kGetAccessTokenURLString URLEncodedString],
					  [queryString URLEncodedString]];
	}
	[queryString release];
	if (DEBUG) CSLog(@"===> baseString : [%@]", baseString);

	// ------------------------------
	// signing
	NSString* keyForSigning = [[[self oauthParamForKey:kNateKeyOAuthConsumerSecret]
								URLEncodedString] stringByAppendingString:@"&"];
	if (requestToken == NO)
	{
		keyForSigning = [keyForSigning stringByAppendingFormat:@"%@",
						 [[self oauthParamForKey:kNateKeyOAuthTokenSecret] URLEncodedString]];
	}
	if (DEBUG) CSLog(@"===> keyForSigning : [%@]", keyForSigning);

	const char *cKey  = [keyForSigning cStringUsingEncoding:NSASCIIStringEncoding];
	const char *cData = [baseString cStringUsingEncoding:NSASCIIStringEncoding];

	unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
	CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
	NSData* aHMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];

	NSString* oauthSignature = [[aHMAC base64EncodedString] retain];
	[aHMAC release];
	if (DEBUG) CSLog(@"===> oauthSignature : [%@]", oauthSignature);

	return [oauthSignature autorelease];
}

- (NSString*)generateOAuthHeaderWithOAuthNonce:(NSString*)oauthNonce
			   andOAuthTimestamp:(NSString*)oauthTimestamp
			   andOAuthSignature:(NSString*)oauthSignature
				 andRequestToken:(BOOL)requestToken
{
	NSMutableString* authHeader = [[NSMutableString alloc] initWithString:@"OAuth "];
	if (requestToken)
	{
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthVersion, [[self oauthParamForKey:kNateKeyOAuthVersion]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthNonce, [oauthNonce URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthTimestamp, oauthTimestamp];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthConsumerKey, [[self oauthParamForKey:kNateKeyOAuthConsumerKey] URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthCallback, [[self oauthParamForKey:kNateKeyOAuthCallback]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthSignatureMethod, [[self oauthParamForKey:kNateKeyOAuthSignatureMethod]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthSignature, [oauthSignature URLEncodedString]];
	}
	else
	{
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthVersion, [[self oauthParamForKey:kNateKeyOAuthVersion]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthNonce, [oauthNonce URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthTimestamp, oauthTimestamp];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthConsumerKey, [[self oauthParamForKey:kNateKeyOAuthConsumerKey] URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthToken, [[self oauthParamForKey:kNateKeyOAuthToken]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthVerifier, [[self oauthParamForKey:kNateKeyOAuthVerifier]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthSignatureMethod, [[self oauthParamForKey:kNateKeyOAuthSignatureMethod]  URLEncodedString]];
		[authHeader appendString:@","];
		[authHeader appendFormat:@"%@=\"%@\"", kNateKeyOAuthSignature, [oauthSignature URLEncodedString]];
	}

	return [authHeader autorelease];
}



#pragma mark -



- (void)startSignIn
{
	//if (DEBUG) CSLog(@"==============================================");

	// *************************
	// Request Token 요청
	// *************************
	NSDictionary* dicOAuthRequestToken = [[self requestOAuthRequestToken] retain];
	if (dicOAuthRequestToken == nil)
	{
		return;
	}

	[m_oauthParams addEntriesFromDictionary:dicOAuthRequestToken];
	[dicOAuthRequestToken release];


	//if (DEBUG) CSLog(@"==============================================");

	// *************************
	// 인증화면 요청
	// *************************
	NSString* urlString = [kOAuthAuthorizeURLString stringByAppendingFormat:@"?%@=%@",
						   kNateKeyOAuthToken, [m_oauthParams objectForKey:kNateKeyOAuthToken]];

	//if (DEBUG) CSLog(@"===> urlString : [%@]", urlString);
	NSURL* aURL = [[NSURL alloc] initWithString:urlString];
	NSURLRequest* aRequest = [[NSURLRequest alloc] initWithURL:aURL];
	[aURL release];

	m_webView.delegate = self;
	m_webView.scalesPageToFit = YES;
	[m_webView loadRequest:aRequest];
	[aRequest release];
}


- (NSDictionary*)requestOAuthRequestToken
{
	// *************************
	// Request Token 요청
	// *************************

	NSURL* aURL = [[NSURL alloc] initWithString:kGetRequestTokenURLString];
	NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:aURL];
	[aURL release];

	[urlRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
	[urlRequest setTimeoutInterval:kHTTPRequestTimeout];

	[urlRequest setHTTPMethod:@"POST"];
	[urlRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
	[urlRequest setValue:CurrentLanguage() forHTTPHeaderField:@"Accept-Language"];
	[urlRequest setValue:@"0" forHTTPHeaderField:@"Content-Length"];


	NSString* oauthNonce = [[CSNateOAuthResult generateOAuthNonce] retain];
	NSString* oauthTimestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
	NSString* oauthSignature = [[self generateOAuthSignatureWithOAuthNonce:oauthNonce
														 andOauthTimestamp:oauthTimestamp
														   andRequestToken:YES] retain];

	//if (DEBUG) CSLog(@"===> oauthNonce : [%@]", oauthNonce);
	//if (DEBUG) CSLog(@"===> oauthSignature : [%@]", oauthSignature);

	NSString* authHeader = [[self generateOAuthHeaderWithOAuthNonce:oauthNonce
												  andOAuthTimestamp:oauthTimestamp
												  andOAuthSignature:oauthSignature
													andRequestToken:YES] retain];
	[oauthSignature release];
	[oauthNonce release];


	if (DEBUG) CSLog(@"===> authHeader : [%@]", authHeader);
	[urlRequest setValue:authHeader forHTTPHeaderField:@"Authorization"];
	[authHeader release];

	NSError* error = nil;
	NSHTTPURLResponse* urlResponse = nil;
	NSData* responseData = [NSURLConnection sendSynchronousRequest:urlRequest
												 returningResponse:&urlResponse
															 error:&error];
	[urlRequest release];
	if (error != nil)
	{
		//if (DEBUG) CSLog(@"===> Error : [%@]", error);
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
		{
			[m_delegate nateOAuthViewController:self
							   didFailWithError:error];
		}
		[self dismissView];
		return nil;
	}

	//if (DEBUG) CSLog(@"===> urlResponse : [%d]", [urlResponse statusCode]);
	//if (DEBUG) CSLog(@"===> urlResponse header : [%@]", [urlResponse allHeaderFields]);
	NSString* responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

	//if (DEBUG) CSLog(@"===> responseString : %@", responseString);
	if (urlResponse != nil && [urlResponse statusCode] != 200)
	{
		error = [[NSError alloc] initWithDomain:@"etcErrDomain"
										   code:[urlResponse statusCode]
									   userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
												 responseString, NSLocalizedDescriptionKey,
												 nil]];
		[responseString release];
		//if (DEBUG) CSLog(@"===> Error : %@", error);
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
		{
			[m_delegate nateOAuthViewController:self
							   didFailWithError:error];
		}
		[self dismissView];
		return nil;
	}


	//if (DEBUG) CSLog(@"===> responseString : [%@]", responseString);
	NSMutableDictionary* dicOAuthRequestToken = [[CSCommon parseQueryString:responseString] retain];
	[responseString release];

	if (dicOAuthRequestToken == nil || [dicOAuthRequestToken count] <= 0)
	{
		error = [[NSError alloc] initWithDomain:@"etcErrDomain"
										   code:101
									   userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
												 @"request token error", NSLocalizedDescriptionKey,
												 nil]];
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
		{
			[m_delegate nateOAuthViewController:self
							   didFailWithError:error];
		}
		[self dismissView];
		return nil;
	}

	if ([[dicOAuthRequestToken objectForKey:kNateKeyOAuthCallbackConfirmed] isEqualToString:@"true"] == NO)
	{
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didRejectWithAuthResult:)])
		{
			[m_delegate nateOAuthViewController:self
						didRejectWithAuthResult:nil];
		}
		[self dismissView];
		return nil;
	}

	//if (DEBUG) CSLog(@"===> dicOAuthRequestToken : [%@]", dicOAuthRequestToken);
	return [dicOAuthRequestToken autorelease];
}



// callback url 여부를 확인한다.
// return : 0 - rejected, < 0 - processing, > 0 - accepted
- (NSInteger)finalRequestToken:(NSURLRequest*)request
{
	NSString* urlPath = [NSString stringWithFormat:@"%@://%@%@",
						 [[request URL] scheme], [[request URL] host], [[request URL] path]];

	//if (DEBUG) CSLog(@"===> finalRequestToken : [%@]", urlPath);
	if ([urlPath isEqualToString:[self oauthParamForKey:kNateKeyOAuthCallback]])
	{
		//BOOL delegateCalled = NO;
		NSMutableDictionary* params = [[CSCommon parseQueryString:[[request URL] query]] retain];
		//if (DEBUG) CSLog(@"===> params 00 : %@", params);

		[m_oauthParams addEntriesFromDictionary:params];
		[params release];

		CSNateOAuthResult* oauthResult = [[CSNateOAuthResult alloc] initWithDictionary:m_oauthParams];
		//if (DEBUG) CSLog(@"===> params 01 : %@", m_oauthParams);
		if ([oauthResult isAuthorized])
		{
			if ([oauthResult hasNateOnProfile])
			{
				CSAssert(FALSE, @"assert");
//				[self stopProgressIndicator];
//				if (m_delegate != nil &&
//					[m_delegate respondsToSelector:@selector(nateOAuthViewController:didLoginWithAuthResult:)])
//				{
//					[m_delegate nateOAuthViewController:self
//								 didLoginWithAuthResult:[oauthResult autorelease]];
//				}
			}
		}
		else
		{
			[self stopProgressIndicator];
			if (m_delegate != nil &&
				[m_delegate respondsToSelector:@selector(nateOAuthViewController:didRejectWithAuthResult:)])
			{
				[m_delegate nateOAuthViewController:self
							didRejectWithAuthResult:[oauthResult autorelease]];
			}
			return 0;
		}

		return 1;
	}

	return -1;
}


/**
 @return result param, 실패시 nil
 */
- (NSDictionary*)requestOAuthAccessToken
{
	//if (DEBUG) CSLog(@"==============================================");
	//if (DEBUG) CSLog(@"===> oauthParam : %@", m_oauthParams);

	// *************************
	// Access Token 요청
	// *************************
	NSURL* aURL = [[NSURL alloc] initWithString:kGetAccessTokenURLString];
	NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:aURL];
	[aURL release];

	[urlRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
	[urlRequest setTimeoutInterval:kHTTPRequestTimeout];

	[urlRequest setHTTPMethod:@"POST"];
	[urlRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
	[urlRequest setValue:CurrentLanguage() forHTTPHeaderField:@"Accept-Language"];
	[urlRequest setValue:@"0" forHTTPHeaderField:@"Content-Length"];

	NSString* oauthNonce = [[CSNateOAuthResult generateOAuthNonce] retain];
	NSString* oauthTimestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
	NSString* oauthSignature = [[self generateOAuthSignatureWithOAuthNonce:oauthNonce
														 andOauthTimestamp:oauthTimestamp
														   andRequestToken:NO] retain];

	//if (DEBUG) CSLog(@"===> oauthNonce : [%@]", oauthNonce);
	//if (DEBUG) CSLog(@"===> oauthSignature : [%@]", oauthSignature);

	NSString* authHeader = [[self generateOAuthHeaderWithOAuthNonce:oauthNonce
												  andOAuthTimestamp:oauthTimestamp
												  andOAuthSignature:oauthSignature
													andRequestToken:NO] retain];
	[oauthSignature release];
	[oauthNonce release];


	if (DEBUG) CSLog(@"===> authHeader : [%@]", authHeader);
	[urlRequest setValue:authHeader forHTTPHeaderField:@"Authorization"];
	[authHeader release];

	NSError* error = nil;
	NSHTTPURLResponse* urlResponse = nil;
	NSData* responseData = [NSURLConnection sendSynchronousRequest:urlRequest
												 returningResponse:&urlResponse
															 error:&error];
	[urlRequest release];
	if (error != nil)
	{
		//if (DEBUG) CSLog(@"===> Error : [%@]", error);
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
		{
			[m_delegate nateOAuthViewController:self
							   didFailWithError:error];
		}
		[self dismissView];
		return nil;
	}

	//if (DEBUG) CSLog(@"===> urlResponse : [%d]", [urlResponse statusCode]);
	//if (DEBUG) CSLog(@"===> urlResponse header : [%@]", [urlResponse allHeaderFields]);
	NSString* responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

	//if (DEBUG) CSLog(@"===> responseString : %@", responseString);
	if (urlResponse != nil && [urlResponse statusCode] != 200)
	{
		error = [[NSError alloc] initWithDomain:@"etcErrDomain"
										   code:[urlResponse statusCode]
									   userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
												 responseString, NSLocalizedDescriptionKey,
												 nil]];
		[responseString release];
		//if (DEBUG) CSLog(@"===> Error : %@", error);
		[self stopProgressIndicator];
		if (m_delegate != nil &&
			[m_delegate respondsToSelector:@selector(nateOAuthViewController:didFailWithError:)])
		{
			[m_delegate nateOAuthViewController:self
							   didFailWithError:error];
		}
		[self dismissView];
		return nil;
	}


	//if (DEBUG) CSLog(@"===> responseString : [%@]", responseString);
	NSMutableDictionary* dicOAuthRequestToken = [[CSCommon parseQueryString:responseString] retain];
	[responseString release];

	return [dicOAuthRequestToken autorelease];
}



#pragma mark -

- (void)requestNateOnProfile
{
	//if (DEBUG) CSLog(@"\n\n\n\n\n==============================================");
	if (m_nateRequest != nil)
	{
		[m_nateRequest release];
		m_nateRequest = nil;
	}

	// *************************
	// NateOn Profile 요청
	// *************************

	m_nateRequest = [[CSNateRequest alloc] initWithNateOAuthResult:m_oauthResult];
	m_nateRequest.nateTag = kNateTagNateOnProfile;
	m_nateRequest.delegate = self;

	NSMutableDictionary* params = [[NSMutableDictionary alloc] init];
	[m_nateRequest requestWithMethodName:CSNateRequestNateOnGetProfile
							   andParams:[params autorelease]];
}

@end
